﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Hosting;
using System.Xml;
using umbraco.cms.businesslogic.member;
using umbraco.DataLayer;
using System.Threading;

namespace Designit.Umb.Newsletter.Bll
{
    public class EmbedNewsletter
    {
        public static string Emb(string templateAlias)
        {
            var template = TemplateHandler.GetTemplateFromAlias(templateAlias);

            //replace the custom body tag field
            var regex = @"<designit.Newsletter:Item field=""bodytext""></designit.Newsletter:Item>";
            const string regex1 = @"<designit.Newsletter:Item field=""bodytext""/>";
            string replacement = @"<textarea id=""contentEditor"" name=""contentEditor"" style=""width:100%"" runat=""server""></textarea>";
            string result = Regex.Replace(template, regex + "|" + regex1, replacement, RegexOptions.IgnoreCase);


            #region tinymce
            //"build" the tinymce with custom button
            var sb = new StringBuilder();
            var rnd = Guid.NewGuid();
            sb.AppendLine(string.Format(@"<script src=""/umbraco/plugins/tinymce3/tinymce3tinymceCompress.aspx?rnd={0}&amp;module=gzipmodule&amp;themes=umbraco&amp;plugins=contextmenu,table,umbracomacro,paste,inlinepopups,media,advimage,advlink,noneditable&amp;languages=en"" type=""text/javascript""></script>", rnd));
            sb.AppendLine(@"<link rel='stylesheet' href='/umbraco_client/menuicon/style.css' />");
            sb.AppendLine(@"<link rel='stylesheet' href='/umbraco_client/tabview/style.css' />");
            sb.AppendLine(@"<script type=""text/javascript"">");
            sb.AppendLine(@"// Creates a new plugin class and a custom listbox");
            sb.AppendLine(@"tinymce.create('tinymce.plugins.tagListPlugin', {");
            sb.AppendLine(@"createControl: function(n, cm) {");
            sb.AppendLine(@"switch (n) {");
            sb.AppendLine(@"case 'tagmenubutton':");
            sb.AppendLine(@"var c = cm.createMenuButton('tagmenubutton', {");
            sb.AppendLine(@"title : 'Insert newsletter field',");
            sb.AppendLine(@"image : '/umbraco/images/editor/button_menu.gif',");
            sb.AppendLine(@"icons : false");
            sb.AppendLine(@"});");
            sb.AppendLine(@"");
            sb.AppendLine(@"c.onRenderMenu.add(function(c, m) {");
            sb.AppendLine(@"var sub;");
            sb.AppendLine(@"m.add({title : '@SubscriberName', onclick : function() {");
            sb.AppendLine(@"tinyMCE.activeEditor.execCommand('mceInsertContent', false, '@SubscriberName');");
            sb.AppendLine(@"}});");
            sb.AppendLine(@"m.add({title : '@CompanyName', onclick : function() {");
            sb.AppendLine(@"tinyMCE.activeEditor.execCommand('mceInsertContent', false, '@CompanyName');");
            sb.AppendLine(@"}});");
            //sb.AppendLine(@"m.add({title : '@Unsubscribe', onclick : function() {");
            //sb.AppendLine(@"tinyMCE.activeEditor.execCommand('mceInsertContent', false, '@Unsubscribe');");
            //sb.AppendLine(@"}});");
            sb.AppendLine(@"m.add({title : '@CompanyMail', onclick : function() {");
            sb.AppendLine(@"tinyMCE.activeEditor.execCommand('mceInsertContent', false, '@CompanyMail');");
            sb.AppendLine(@"}});");
            sb.AppendLine(@"});");
            sb.AppendLine(@"");
            sb.AppendLine(@"// Return the new menu button instance");
            sb.AppendLine(@"return c;");
            sb.AppendLine(@"}");
            sb.AppendLine(@"");
            sb.AppendLine(@"return null;");
            sb.AppendLine(@"}");
            sb.AppendLine(@"});");
            sb.AppendLine(@"");
            sb.AppendLine(@"// Register plugin with a short name");
            sb.AppendLine(@"tinymce.PluginManager.add('tagList', tinymce.plugins.tagListPlugin);");
            sb.AppendLine(@"");
            sb.AppendLine(@"tinyMCE.init({");
            sb.AppendLine(@"mode:'exact',");
            sb.AppendLine(@"theme:'umbraco',");
            sb.AppendLine(@"umbraco_path:'/umbraco',");
            sb.AppendLine(@"theme_umbraco_toolbar_location:'top',");
            sb.AppendLine(@"skin:'umbraco',");
            sb.AppendLine(@"inlinepopups_skin :'umbraco',");
            sb.AppendLine(@"auto_resize : true,");
            sb.AppendLine(@"plugins:'contextmenu,table,-tagList,paste,inlinepopups,media,umbracocss,advimage,advlink,noneditable',");
            sb.AppendLine(@"umbraco_advancedMode:true,");
            sb.AppendLine(@"umbraco_maximumDefaultImageWidth:'500',");
            sb.AppendLine(@"language:'en',");
            sb.AppendLine(@"content_css:'',");
            sb.AppendLine(@"theme_umbraco_styles:'',");
            sb.AppendLine(@"theme_umbraco_buttons1:'tagmenubutton,code,separator,undo,redo,cut,copy,pasteword',");
            sb.AppendLine(@"theme_umbraco_buttons2:'bold,italic,separator,bullist,numlist,outdent,indent,separator,link,unlink,separator,image,table,separator,charmap',");
            sb.AppendLine(@"theme_umbraco_buttons3:'',");
            sb.AppendLine(@"theme_umbraco_toolbar_align:'left',");
            sb.AppendLine(@"setup : function(ed) {");
            sb.AppendLine(@"ed.onKeyUp.add(function(ed, e) {");
            sb.AppendLine(@"parent.resizeIframe('iframe1');");
            sb.AppendLine(@"});");
            sb.AppendLine(@"},");
            sb.AppendLine(@"theme_umbraco_disable:'help,visualaid,subscript,justifyright,justifyfull,inserthorizontalrule,underline,removeformat,strikethrough,media,superscript,justifyleft,justifycenter',");
            sb.AppendLine(@"theme_umbraco_path :true,");
            sb.AppendLine(@"extended_valid_elements:'div[*]',");
            sb.AppendLine(@"document_base_url:'/',");
            sb.AppendLine(@"relative_urls:false,");
            sb.AppendLine(@"remove_script_host:true,");
            sb.AppendLine(@"event_elements:'div',");
            sb.AppendLine(@"paste_auto_cleanup_on_paste:true,");
            sb.AppendLine(@"valid_elements:'+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|' + ");
            sb.AppendLine(@"'ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],' + ");
            sb.AppendLine(@"'-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,' + ");
            sb.AppendLine(@"'img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel],' + ");
            sb.AppendLine(@"'-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],' + ");
            sb.AppendLine(@"'-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],' + ");
            sb.AppendLine(@"'thead[id|class],tfoot[id|class],-td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],' + ");
            sb.AppendLine(@"'-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],' + ");
            sb.AppendLine(@"'-span[class|align],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align],-h2[id|dir|class|align],' + ");
            sb.AppendLine(@"'-h3[id|dir|class|align],-h4[id|dir|class|align],-h5[id|dir|class|align],-h6[id|style|dir|class|align],hr[class|style],' + ");
            sb.AppendLine(@"'dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[classid|width|height|codebase|*],' + ");
            sb.AppendLine(@"'param[name|value|_value],embed[type|width|height|src|*],map[name],area[shape|coords|href|alt|target],bdo,button,code',");
            sb.AppendLine(@"invalid_elements:'font',");
            sb.AppendLine(@"entity_encoding:'raw',");
            sb.AppendLine(@"theme_umbraco_versionId:'" + rnd + @"',");
            sb.AppendLine(@"elements:'contentEditor'");
            sb.AppendLine(@"});");
            sb.AppendLine(@"function getTinyContent(){");
            sb.AppendLine(@"var ed = tinyMCE.get('contentEditor');");
            sb.AppendLine(@"return ed.getContent();");
            sb.AppendLine(@"}");
            sb.AppendLine(@"function setTinyContent(htmlText){");
            sb.AppendLine(@"var ed = tinyMCE.get('contentEditor');");
            sb.AppendLine(@"ed.setContent(htmlText);");
            sb.AppendLine(@"}");
            sb.AppendLine(@"</script>");
            #endregion

            //check if header field exist in template:
            regex = "<head[^>]*>(.*?)</head>";
            if (Regex.IsMatch(template, regex, RegexOptions.IgnoreCase | RegexOptions.Singleline))
            {
                //insert javascript at the end of <head> field
                regex = @"</head>";
                replacement = sb.ToString() + "</head>";
                result = Regex.Replace(result, regex, replacement, RegexOptions.IgnoreCase);
                return result;
            }
            else
            {
                sb.AppendLine(result);
                return sb.ToString();
            }
        }

        public static string Embstep4(string templateAlias)
        {
            var template = Bll.TemplateHandler.GetTemplateFromAlias(templateAlias);

            //retrieve tinyMce content
            var campContent = umbraco.BusinessLogic.Application.SqlHelper.ExecuteScalar<string>("select tempContent from newsLetterCampaignTempContent where id=1");
            return EmbContentAndTemplate(template, campContent);
        }

        public static string EmbSend(string template, string content, string fromName, string fromMail)
        {
            var ret = EmbContentAndTemplate(template, content);

            //replace @companyname
            ret = Regex.Replace(ret, "@CompanyName", fromName, RegexOptions.IgnoreCase);

            //replace @companymail
            ret = Regex.Replace(ret, "@CompanyMail", fromMail, RegexOptions.IgnoreCase);

            return ret;
        }

        public static string EmbContentAndTemplate(string template, string content)
        {
            //replace the custom body tag field
            const string regex = @"<designit.Newsletter:Item field=""bodytext""></designit.Newsletter:Item>";
            const string regex1 = @"<designit.Newsletter:Item field=""bodytext""/>";
            var replacement = content;
            var result = Regex.Replace(template, regex + "|" + regex1, replacement, RegexOptions.IgnoreCase);

            return result;

        }

        public static void SendCampaign(int campaignId)
        {
            var t = new Thread(new ParameterizedThreadStart(SendCampaignEngine));
            t.Start(campaignId);
        }

        public static void SendCampaignEngine(object oCampmapignId)
        {
            var campaignId = (int)oCampmapignId;
            try
            {
                var campTitle = string.Empty;
                var campFromMail = string.Empty;
                var campSubject = string.Empty;
                var content = string.Empty;
                var campTrack = false;
                var campGoogle = false;

                umbraco.BusinessLogic.Application.SqlHelper.ExecuteNonQuery(
                    "UPDATE newsletterCampaignNewsletter SET campstatus='sending' WHERE id=@campId",
                    umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campId", campaignId));

                using (
                    var reader =
                        umbraco.BusinessLogic.Application.SqlHelper.ExecuteReader(
                            "Select * from newsLetterCampaignNewsletter where id =@campaignId",
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campaignId", campaignId)))
                {
                    while (reader.Read())
                    {
                        var companyName = reader.GetString("campfrom");
                        var companyMail = reader.GetString("campreplyMail");
                        campTrack = Convert.ToBoolean(reader.GetString("campTrack"));
                        campGoogle = Convert.ToBoolean(reader.GetString("campGoogle"));
                        campTitle = reader.GetString("camptitle");
                        campFromMail = reader.GetString("campreplyMail");
                        campSubject = reader.GetString("campsubject");
                        content = EmbSend(reader.GetString("campTemplatecontent"), reader.GetString("campcontent"),
                                          companyName, companyMail);
                    }
                }

                //set the smtp client and send the mail
                var mailSettings = Bll.MailSettings.Get();

                var cl = new SmtpClient(mailSettings.SmtpServer, mailSettings.SmtpPort);
                if (mailSettings.SmtpAuth)
                {
                    cl.Credentials = new NetworkCredential(mailSettings.MailServerUsername, mailSettings.MailServerPassword);
                }

                var currentDomain = Helper.GetCurrentHostUrl();

                //replace href tags to redirect to counter page and store values of link in db
                var regex = @"<a href=""(.*?)</a>";
                foreach (var match in Regex.Matches(content, regex, RegexOptions.IgnoreCase))
                {
                    var lokal = false;
                    var url = Regex.Match(match.ToString(), @"""(.*?)""", RegexOptions.IgnoreCase).ToString();
                    url = url.Substring(1, url.Length - 2);
                    var replaceString = Regex.Match(match.ToString(), @"href=""(.*?)""").ToString();
                    if (url.StartsWith("/{localLink"))
                    {
                        url = umbraco.library.NiceUrlFullPath(Int32.Parse(url.Substring(12, url.Length - 13)));
                        url = currentDomain + url;
                        lokal = true;
                    }
                    if (campTrack)
                    {
                        if (campGoogle)
                        {
                            var tracked = false;
                            //check if the linke is within currentDomain
                            if (url.Contains(currentDomain))
                            {
                                content = InsertGoogleAnalyticsCode(campTitle, content, url, match);
                                tracked = true;
                            }

                            //check if it's a trusted site
                            if (!tracked)
                            {
                                foreach (var analyticsSite in mailSettings.GoogleAnalyticsSites)
                                {
                                    var trustedSite = analyticsSite;
                                    if (trustedSite.Contains("www."))
                                        trustedSite = trustedSite.Substring(trustedSite.IndexOf('.') + 1);
                                    else if (trustedSite.StartsWith("http"))
                                        trustedSite = trustedSite.Substring(trustedSite.IndexOf('/') + 2);

                                    if (url.Contains(trustedSite))
                                    {
                                        content = InsertGoogleAnalyticsCode(campTitle, content, url, match);
                                        tracked = true;
                                    }   
                                }
                            }

                            //track with own track
                            if (!tracked)
                                content = InsertOwnAnalyticsCode(content, replaceString, campaignId, url);

                        }
                        else
                            content = InsertOwnAnalyticsCode(content, replaceString, campaignId, url);

                    }
                    else if (lokal)
                    {
                        var regexLocal = string.Format(@"href=""{0}""", url);
                        content = Regex.Replace(content, replaceString, regexLocal, RegexOptions.IgnoreCase);

                    }
                }

                //Create an email and assign the sender of the mail
                var campaignMail = new MailMessage {From = new MailAddress(campFromMail)};
                var subject = campSubject;

                //Getting the members to send to, assign the sending and send
                var members = Helper.GetMembersForCampaign(campaignId);
                foreach (var member in members)
                {
                    var alreadySent =
                        umbraco.BusinessLogic.Application.SqlHelper.ExecuteScalar<bool>(
                            "SELECT Send FROM newsLetterSendMail WHERE campaignId = @campaignId AND memberId = @memberId",
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@memberId", member.Id),
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campaignId", campaignId)
                            );

                    if (!alreadySent)
                    {
                        var mail = member.Email;
                        campaignMail.To.Add(new MailAddress(mail));


                        //replace @Unsubscribe
                        regex = "@Unsubscribe";
                        //var replacement = string.Format(@"<a title=""Unsubscribe"" href=""{0}?mail={1}"" target=""_blank"">Unsubscribe</a>", unsubscribe, mail);
                        var replacement = string.Format("{0}?mail={1}", mailSettings.UnsubscribePage, mail);
                        var finalCont = Regex.Replace(content, regex, replacement, RegexOptions.IgnoreCase);
                        //var finalCont = content.Replace("@unsubscribe", string.Format("{0}?mail={1}", unsubscribe, mail));

                            if (!string.IsNullOrEmpty(campaignMail.Headers.Get("Content-Base")))
                                campaignMail.Headers["Content-Base"] = currentDomain;
                            else
                                campaignMail.Headers.Add("Content-Base", currentDomain);

                        //set subject of mail
                        campaignMail.Subject = subject;

                        //set the text of the mail
                        campaignMail.IsBodyHtml = true;

                        //replace @SubscriberName
                        regex = "@SubscriberName";
                        replacement = member.LoginName;
                        finalCont = Regex.Replace(finalCont, regex, replacement, RegexOptions.IgnoreCase);
                        finalCont = Helper.InsertHostIntoLink(finalCont);

                        campaignMail.Body = finalCont;

                        cl.Send(campaignMail);

                        umbraco.BusinessLogic.Application.SqlHelper.ExecuteNonQuery(
                            "insert into newsLetterSendMail(campaignId, memberId, Send) values(@campaignId, @memberId, @Send)",
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campaignId", campaignId),
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@memberId", member.Id),
                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@Send", "true"));

                        campaignMail.To.Clear();
                        //Thread.Sleep(TimeSpan.FromSeconds(5));
                    }
                }
                umbraco.BusinessLogic.Application.SqlHelper.ExecuteNonQuery(
                    "UPDATE newsletterCampaignNewsletter SET campstatus='sent' WHERE id=@campId",
                    umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campId", campaignId));
            }
            catch
            {
                umbraco.BusinessLogic.Application.SqlHelper.ExecuteNonQuery("UPDATE newsletterCampaignNewsletter SET campstatus='error' WHERE id=@campId",
                                                                            umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campId", campaignId));
            }
        }

        private static string InsertOwnAnalyticsCode(string content, string replaceString, int campaignId, string url)
        {
            var currentDomain = Bll.Helper.GetCurrentHostUrl();
            var trackerPage = currentDomain + "designit/newsletter/tracking/tracking.aspx";

            umbraco.BusinessLogic.Application.SqlHelper.ExecuteNonQuery(
                                    "insert into newsletterTracking(campaignId, url, clicks) values(@campaignId, @url, 0)",
                                    umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@campaignId",
                                                                                                campaignId),
                                    umbraco.BusinessLogic.Application.SqlHelper.CreateParameter("@url", url));
            //check if url contains parameters
            var regexLinkReplace = "";
            if (url.Contains("?"))
                regexLinkReplace = @"href=""" + trackerPage + "?redirect=" + url + "&campaign=" + campaignId + @"""";
            else
                regexLinkReplace = @"href=""" + trackerPage + "?redirect=" + url + "&campaign=" + campaignId + @"""";

            content = Regex.Replace(content, replaceString, regexLinkReplace, RegexOptions.IgnoreCase);

            return content;
        }

        private static string InsertGoogleAnalyticsCode(string campTitle, string content, string url, object match)
        {
            var campaignName = campTitle;
            campaignName = Regex.Replace(campaignName, @"\s", "+", RegexOptions.IgnoreCase);
            var markedText = Regex.Match(match.ToString(), @""">(.*?)</a>", RegexOptions.IgnoreCase).ToString();
            markedText = markedText.Substring(2, markedText.Length - 6);
            var markedNonWhiteSpaceText = Regex.Replace(markedText, @"\s", "+", RegexOptions.IgnoreCase);
            //check if url contains parameters
            var regexLinkReplace = "";
            if (url.Contains("?"))
            {
                regexLinkReplace = @"<a href=""" + url +
                                   @"&utm_source=newsletter&utm_medium=email&utm_term=" +
                                   markedNonWhiteSpaceText + "&utm_campaign=" + campaignName +
                                   @""">" +
                                   markedText + "</a>";
            }
            else
            {
                regexLinkReplace = @"<a href=""" + url +
                                   @"?utm_source=newsletter&utm_medium=email&utm_term=" +
                                   markedNonWhiteSpaceText + "&utm_campaign=" + campaignName +
                                   @""">" +
                                   markedText + "</a>";
            }

            content = Regex.Replace(content, match.ToString(), regexLinkReplace, RegexOptions.IgnoreCase);
            return content;
        }
    }

}
